importScripts('../workers/sphericalMercator.js');
importScripts('../workers/geoutils.js');

var mercator = new SphericalMercator({size: geoutils.basePlaneDimension});
var imagery = {};
var working = false;

self.addEventListener('message', function (e) {

    var cb = e.data;
    // if (cb.restore) {
    //        imagery[cb.restore] = false
    //        return
    // }
    var zoom = cb[0];
    var payload = cb[1];
    var bounds = cb[2]; // [[lng, lat] * 4, [lng0, lat0]]
    var dealloced = cb[3];
    var coordSystem = cb[4];
    var extent = cb[5];

    if (dealloced) {
        (dealloced || []).forEach(function (tile) {
            delete imagery[tile];
        });
    }

    if (!payload && !bounds) return;

    // unproject world pixels to coordinates
    var box = bounds;

    if (payload) {
        box = payload.map(function (corner) {
            var pt = corner ? corner : {
                x: corner.x * geoutils.basePlaneDimension / 2,
                z: corner.y * geoutils.basePlaneDimension / 2
            }
            var lngLat = mercator.ll([pt.x + geoutils.basePlaneDimension / 2, pt.z + geoutils.basePlaneDimension / 2], 0);
            if (coordSystem && (coordSystem == 'gcj' || coordSystem == 'gcj02')) {
                lngLat = geoutils.gcj02_to_wgs84(lngLat[0], lngLat[1]);
                lngLat = [lngLat.lng, lngLat.lat];
            }
            return lngLat;
        });
    }

    box = {
        "type": "Polygon",
        "coordinates": [box],
    };

    // using tile-cover, figure out which tiles are inside viewshed and put in zxy order
    var satelliteTiles = geoutils.tiles(box, {min_zoom: zoom, max_zoom: zoom}).map(function (xyz) {
        return [xyz[2], xyz[0], xyz[1]];
    });

    if (extent && extent.length > 3) {
        var zExtents = {};
        satelliteTiles.forEach(function (zxy) {
            var z = zxy[0], x = zxy[1], y = zxy[2];
            if (!zExtents[z]) {
                zExtents[z] = [x, x, y, y];
            } else {
                zExtents[z][0] = Math.min(x, zExtents[z][0]);
                zExtents[z][1] = Math.max(x, zExtents[z][1]);
                zExtents[z][2] = Math.min(y, zExtents[z][2]);
                zExtents[z][3] = Math.max(y, zExtents[z][3]);
            }
        });
        Object.keys(zExtents).forEach(function (z) {
            var minX = extent[0] + zExtents[z][0];
            var maxX = extent[1] + zExtents[z][1];
            var minY = extent[2] + zExtents[z][2];
            var maxY = extent[3] + zExtents[z][3];
            for (var x = minX; x <= maxX; x++) {
                satelliteTiles.push([z, x, minY]);
                satelliteTiles.push([z, x, maxY]);
            }
            for (var y = minY + 1; y <= maxY - 1; y++) {
                satelliteTiles.push([z, minX, y]);
                satelliteTiles.push([z, maxX, y]);
            }
        });
    }

    if (satelliteTiles.length == 0) return;

    var imageTiles = [];

    for (var s = 0; s < satelliteTiles.length; s++) {
        var tile = satelliteTiles[s];

        // make sure this tile isn't already downloaded
        if (!imagery[tile]) {
            imagery[tile] = true;
            imageTiles.push(tile);
        }
    }

    var elevations = {};

    // assemble list of elevations, as grandparent tiles of imagery
    for (var t = 0; t < imageTiles.length; t++) {
        var deslashed = imageTiles[t];
        var grandparent = [deslashed[0] - 2, Math.floor(deslashed[1] / 4), Math.floor(deslashed[2] / 4)];
        if (elevations[grandparent]) {
            elevations[grandparent].push(deslashed);
        } else {
            elevations[grandparent] = [deslashed];
        }
    }

    var elevationTiles = Object.keys(elevations).map(function (triplet) {
        return triplet.split(',').map(function (num) {
            return parseFloat(num);
        });
    });

    var center = null;
    if (box.coordinates.length) {
        center = [0, 0];
        box.coordinates.forEach(function (c) {
            center[0] += c[0];
            center[1] += c[1];
        });
        center[0] /= box.coordinates.length;
        center[1] /= box.coordinates.length;
    }

    if (elevationTiles.length) {
        var cenTile = [0, 0, 0];
        elevationTiles.forEach(function (tile, i) {
            cenTile[1] += tile[1];
            cenTile[2] += tile[2];
        });
        elevationTiles.forEach(function (a, i) {
            a[3] =  (a[1] - cenTile[1]) * (a[1] - cenTile[1]) + (a[2] - cenTile[2]) * (a[2] - cenTile[2]);
        });
        cenTile[1] /= elevationTiles.length;
        cenTile[2] /= elevationTiles.length;
        elevationTiles = elevationTiles.sort(function (a, b) {
            // a before, return -1
            if (a[3] < b[3]) return -1;
            if (a[3] > b[3]) return 1;
            return 0;
        });
    }

    self.postMessage({getTiles: [imageTiles, elevationTiles]});

}, false);